home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / com / internet / stik / gluestik / transdmn.c < prev    next >
C/C++ Source or Header  |  1996-08-31  |  21KB  |  906 lines

  1. #include <string.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <unistd.h>
  5. #include <signal.h>
  6. #include <sys/socket.h>
  7. #include <sys/time.h>
  8. #include <sys/types.h>
  9. #include <netinet/in.h>
  10. #include <netdb.h>
  11. #include <ioctl.h>
  12. #include <fcntl.h>
  13. #include <arpa/nameser.h>    /* for <resolv.h> */
  14. #define __const const        /* grrrr... */
  15. #include <resolv.h>        /* for h_error */
  16. #include <mintbind.h>
  17. #include "global.h"
  18. #include "pipe.h"
  19.  
  20.  
  21. /* MiNTnet's fcntl(FIONREAD) returns this when the socket shuts down, or
  22.    an error condition occurs, or there's no more to read. */
  23. #define NO_LIMIT    0x7FFFFFFFL
  24.  
  25. typedef struct CIB_chain {
  26.   int the_fd;
  27. #ifndef BLOCK_OPEN
  28.   int established;
  29. #endif
  30.   CIB the_CIB;
  31.   struct CIB_chain *next;
  32. } CIB_chain;
  33.  
  34. Daemon_Op OP;
  35. Daemon_Retval RET;
  36. CIB_chain *CIB_list = 0;
  37.  
  38. static int daemon_pipe;
  39.  
  40.  
  41. int init_net()
  42. {
  43.   if (Psemaphore(0, DMN_SEMAPHORE, 0L) < 0) {
  44.     Cconws("Cannot get semaphore for daemon access\r\n");
  45.     return 0;
  46.   }
  47.   /* We own the semaphores when they're created; release them so we can
  48.      re-grab them later */
  49.   Psemaphore(3, DMN_SEMAPHORE, 0L);
  50. #ifdef DEBUG
  51.   if (Psemaphore(0, DEBUG_SEMAPHORE, 0L) < 0) {
  52.     Cconws("Cannot get semaphore for debug log\r\n");
  53.     return 0;
  54.   }
  55.   Psemaphore(3, DEBUG_SEMAPHORE, 0L);
  56. #endif
  57.   return 1;
  58. }
  59.  
  60.  
  61. void dispatch()
  62. {
  63.   PMSG pmsg;
  64.   Daemon_Op *OP;
  65.   Daemon_Retval *RET;
  66.   int n;
  67.  
  68.   for (;;) {
  69.     n = Pmsg(0, DMN_MBOX, &pmsg);
  70.     if (n < 0) {
  71.       exit(1);
  72.     }
  73.     OP = (Daemon_Op *)pmsg.userlong1;
  74.     RET = (Daemon_Retval *)pmsg.userlong2;
  75. #ifdef DEBUG
  76.     debug("sdsd", "Received op ", OP->common.op, " from pid ", pmsg.pid);
  77. #endif
  78.  
  79.     switch (OP->common.op) {
  80.       case OP_TCP_OPEN:
  81.     RET->ret_int16 = do_TCP_open(OP->P_TCP_open.hostaddr,
  82.                      OP->P_TCP_open.port, OP->P_TCP_open.tos,
  83.                      OP->P_TCP_open.obsize);
  84.     break;
  85.       case OP_TCP_CLOSE:
  86.     RET->ret_int16 = do_TCP_close(OP->P_TCP_close.fd,
  87.                       OP->P_TCP_close.timeout);
  88.     break;
  89.       case OP_TCP_SEND:
  90.     RET->ret_int16 = do_TCP_send(OP->P_TCP_send.fd, OP->P_TCP_send.buf,
  91.                      OP->P_TCP_send.buflen);
  92.     break;
  93.       case OP_TCP_WAIT_STATE:
  94.     RET->ret_int16 = do_TCP_wait_state(OP->P_TCP_wait_state.fd,
  95.                        OP->P_TCP_wait_state.state,
  96.                        OP->P_TCP_wait_state.timeout);
  97.     break;
  98.       case OP_UDP_OPEN:
  99.     RET->ret_int16 = do_UDP_open(OP->P_UDP_open.hostaddr,
  100.                      OP->P_UDP_open.port);
  101.     break;
  102.       case OP_UDP_CLOSE:
  103.     RET->ret_int16 = do_UDP_close(OP->P_UDP_close.fd);
  104.     break;
  105.       case OP_UDP_SEND:
  106.     RET->ret_int16 = do_UDP_send(OP->P_UDP_send.fd, OP->P_UDP_send.buf,
  107.                      OP->P_UDP_send.buflen);
  108.     break;
  109.       case OP_CNBYTE_COUNT:
  110.     RET->ret_int16 = do_CNbyte_count(OP->P_CNbyte_count.fd);
  111.     break;
  112.       case OP_CNGET_CHAR:
  113.     RET->ret_int16 = do_CNget_char(OP->P_CNget_char.fd);
  114.     break;
  115.       case OP_CNGET_NDB:
  116.     RET->ret_NDBptr = do_CNget_NDB(OP->P_CNget_NDB.fd);
  117.     break;
  118.       case OP_CNGET_BLOCK:
  119.     RET->ret_int16 = do_CNget_block(OP->P_CNget_block.fd,
  120.                         OP->P_CNget_block.buf,
  121.                         OP->P_CNget_block.len);
  122.     break;
  123.       case OP_RESOLVE:
  124.     RET->ret_int16 = do_resolve(OP->P_resolve.hostname,
  125.                     OP->P_resolve.realname,
  126.                     OP->P_resolve.addrs,
  127.                     OP->P_resolve.naddrs);
  128.     break;
  129.       case OP_CNGETINFO:
  130.     RET->ret_CIBptr = do_CNgetinfo(OP->P_CNgetinfo.fd);
  131.     break;
  132.       case OP_KRMALLOC:
  133.     RET->ret_charptr = do_KRmalloc(OP->P_KRmalloc.size);
  134.     break;
  135.       case OP_KRFREE:
  136.     do_KRfree(OP->P_KRfree.mem);
  137.     RET->ret_int32 = 0;
  138.     break;
  139.       case OP_KRGETFREE:
  140.     RET->ret_int32 = do_KRgetfree(OP->P_KRgetfree.flag);
  141.     break;
  142.       case OP_KRREALLOC:
  143.     RET->ret_charptr = do_KRrealloc(OP->P_KRrealloc.mem,
  144.                         OP->P_KRrealloc.newsize);
  145.     break;
  146.       case OP_GETVSTR:
  147.     RET->ret_charptr = do_getvstr(OP->P_KRfree.mem);
  148.     break;
  149.       default:
  150. #ifdef DEBUG
  151.     debug("sd", "in dispatch(): unrecognized opcode ", OP->common.op);
  152. #endif
  153.         break;
  154.     }
  155. #ifdef DEBUG
  156.     debug("sdsd", "Responding to op ", OP->common.op, " from pid ", pmsg.pid);
  157. #endif
  158.     Pmsg(1, 0xFFFF0000L | pmsg.pid, &pmsg);
  159.     continue;
  160.   }
  161. }
  162.  
  163.  
  164. static int make_CIB(int fd, uint16 protocol, uint16 lport, uint16 rport,
  165.             uint32 rhost, int established)
  166. {
  167.   CIB_chain *C;
  168.   int retval = 1;
  169.  
  170.   C = (CIB_chain *)do_KRmalloc(sizeof(CIB_chain));
  171.   if (!C)
  172.     retval = 0;
  173.   else {
  174.     C->the_fd = fd;
  175. #ifndef BLOCK_OPEN
  176.     C->established = established;
  177. #endif
  178.     C->the_CIB.protocol = protocol;
  179.     C->the_CIB.lport = lport;
  180.     C->the_CIB.rport = rport;
  181.     C->the_CIB.rhost = rhost;
  182.     C->next = CIB_list;
  183.     CIB_list = C;
  184.   }
  185. #ifdef DEBUG
  186.   debug("si", "make_CIB() returns ", retval);
  187. #endif
  188.   return retval;
  189. }
  190.  
  191. static CIB *find_CIB(int fd)
  192. {
  193.   register CIB_chain *C;
  194.   CIB *CC = 0;
  195.  
  196.   for (C = CIB_list; C; C = C->next) {
  197.     if (C->the_fd == fd) {
  198.       CC = &(C->the_CIB);
  199.       break;
  200.     }
  201.   }
  202. #ifdef DEBUG
  203.   debug("sp", "find_CIB() returns ", (void *)CC);
  204. #endif
  205.   return CC;
  206. }
  207.  
  208. static void remove_CIB(int fd)
  209. {
  210.   register CIB_chain *C = CIB_list, *C2;
  211.  
  212.   if (C && C->the_fd == fd) {
  213.     CIB_list = C->next;
  214.     do_KRfree(C);
  215.   } else {
  216.     for (C = CIB_list; C && C->next; C = C->next) {
  217.       if (C->next->the_fd == fd) {
  218.     C2 = C->next;
  219.     C->next = C2->next;
  220.     do_KRfree(C2);
  221.     break;
  222.       }
  223.     }
  224.   }
  225. #ifdef DEBUG
  226.   debug("s", "remove_CIB() done");
  227. #endif
  228. }
  229.  
  230. #ifndef BLOCK_OPEN
  231. /* Blech blech blech.  I really don't like having to keep state info
  232.    like this, but there appears to be no reliable way to get this info
  233.    on the fly. */
  234. static int is_established(int fd)
  235. {
  236.   register CIB_chain *C;
  237.  
  238.   for (C = CIB_list; C; C = C->next) {
  239.     if (C->the_fd == fd) {
  240.       break;
  241.     }
  242.   }
  243. #ifdef DEBUG
  244.   debug("sdsss", "Connection ", fd, " is ",
  245.     (C->established ? "" : "not "), "established");
  246. #endif
  247.   return (C ? C->established : 0);
  248. }
  249.  
  250. static void set_establish(int fd)
  251. {
  252.   register CIB_chain *C;
  253.  
  254.   for (C = CIB_list; C; C = C->next) {
  255.     if (C->the_fd == fd) {
  256.       C->established = 1;
  257.       break;
  258.     }
  259.   }
  260. }
  261. #endif /* BLOCK_OPEN */
  262.  
  263.  
  264. /* Incompatibility:  obsize is ignored.  MiNTnet does its own buffer
  265.    handling. */
  266. int16 do_TCP_open(uint32 hostaddr, int16 port, int16 tos, uint16 obsize)
  267. {
  268.   struct sockaddr_in addr;
  269.   int fd;
  270.   size_t scratch = sizeof(struct sockaddr_in);
  271.  
  272. #ifdef DEBUG
  273.   debug("slslslslsisisis", "Entering TCP_open(", (hostaddr>>24), ".",
  274.     (hostaddr>>16)&0xFFL, ".", (hostaddr>>8)&0xFFL, ".", hostaddr&0xFFL,
  275.     ", ", port, ", ", tos, ", ", obsize, ")");
  276. #endif
  277.   addr.sin_family = AF_INET;
  278.   addr.sin_addr.s_addr = hostaddr;
  279.   addr.sin_port = port;
  280.  
  281.   fd = socket(AF_INET, SOCK_STREAM, 0);
  282.   if (fd < 0) {
  283.     switch (errno) {
  284.       case EMFILE:
  285.     return E_NOCCB;
  286.       case ENOMEM:
  287.     return E_NOMEM;
  288.       case ENOENT:
  289.       case EAFNOSUPPORT:
  290.       case ESOCKTNOSUPPORT:
  291.       case EPROTONOSUPPORT:
  292.       case EPROTOTYPE:
  293.     return -1000 - errno;
  294.       default:
  295.     return E_CONNECTFAIL;
  296.     }
  297.   }
  298.  
  299.   if (hostaddr != 0) {
  300. #ifndef BLOCK_OPEN
  301.     /* From the STiK specs:  "TCP_open() returns immediately, without
  302.        waiting for the connection to establish." */
  303.     if (fcntl(fd, F_SETFL, O_NDELAY) < 0)
  304.       return E_CONNECTFAIL;
  305. #endif
  306.  
  307.     if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
  308.       switch (errno) {
  309.     case EBADF:
  310.     case EISCONN:
  311.       return E_BADHANDLE;
  312.     case EINVAL:
  313.       return E_LISTEN;
  314.     case ETIMEDOUT:
  315.       return E_CNTIMEOUT;
  316.     case ECONNREFUSED:
  317.       return E_REFUSE;
  318.     case EALREADY:
  319.     case EINPROGRESS:
  320.     case EINTR:
  321.       break;
  322.     case EAFNOSUPPORT:
  323.     case EDESTADDRREQ:
  324.     case EOPNOTSUPP:
  325.       return -1000 - errno;
  326.     default:
  327.       return E_CONNECTFAIL;
  328.       }
  329.     }
  330.  
  331.     /* Cobble up the CIB structure for this connection.  The only thing
  332.        we don't yet have is the local port number. */
  333.     
  334.     if (getsockname(fd, (struct sockaddr *)&addr, &scratch) < 0) {
  335.       int the_err = errno;
  336.  
  337.       close(fd);
  338.       switch (the_err) {
  339.     case EBADF:
  340.       return E_BADHANDLE;
  341.     case EINVAL:
  342.     case EOPNOTSUPP:
  343.     default:
  344.       return -1000 - the_err;
  345.       }
  346.     }
  347.     if (!make_CIB(fd, P_TCP, addr.sin_port, port, hostaddr, 0)) {
  348.       close(fd);
  349.       return E_NOMEM;
  350.     }
  351.  
  352. #ifdef DEBUG
  353.     debug("si", "TCP_open() returns socket handle ", fd);
  354. #endif
  355.     return fd;
  356.   } else {
  357.     int in_fd;
  358.     size_t addr_size = sizeof(addr);
  359.  
  360.    /* From the STiK specs:  "If rhost is 0, then the connection becomes
  361.       a LISTEN socket, and waits for a connection request from a remote
  362.       host." */
  363.  
  364.     addr.sin_addr.s_addr = INADDR_ANY;
  365.  
  366.     if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
  367.       switch (errno) {
  368.     case EBADF:
  369.     case EADDRINUSE:
  370.     case EINVAL:
  371.       return E_BADHANDLE;
  372.     case EAFNOSUPPORT:
  373.     case EACCES:
  374.     case EDESTADDRREQ:
  375.       return -1000 - errno;
  376.     default:
  377.       return E_CONNECTFAIL;
  378.       }
  379.     }
  380.  
  381.     if (listen(fd, 5) < 0) {
  382.       int the_err = errno;
  383.  
  384.       close(fd);
  385.       switch (the_err) {
  386.     case EBADF:
  387.       return E_BADHANDLE;
  388.     case EDESTADDRREQ:
  389.     case EOPNOTSUPP:
  390.     case EINVAL:
  391.       return -1000 - the_err;
  392.     default:
  393.       return E_CONNECTFAIL;
  394.       }
  395.     }
  396.  
  397.     /* Incompatibility:  I don't think I can emulate STiK's non-blocking
  398.        LISTEN ports.  STiK can apparently get away with this because it
  399.        replaces the listen()'ed socket with the accept()'ed socket
  400.        in situ; this behavior cannot be reproduced with Berkeley
  401.        sockets.  Hopefully this won't be too much of a problem. */
  402.     if ((in_fd = accept(fd, (struct sockaddr *)&addr, &addr_size)) < 0) {
  403.       int the_err = errno;
  404.  
  405.       close(fd);
  406.       switch (the_err) {
  407.     case EBADF:
  408.       return E_BADHANDLE;
  409.     case EMFILE:
  410.       return E_NOCCB;
  411.     case ENOMEM:
  412.       return E_NOMEM;
  413.     case EOPNOTSUPP:
  414.     case EWOULDBLOCK:
  415.     case ECONNABORTED:
  416.     case EINVAL:
  417.     case EINTR:
  418.       return -1000 - the_err;
  419.     default:
  420.       return E_CONNECTFAIL;
  421.       }
  422.     }
  423.  
  424.     /* In STiK, an accept() apparently "eats" the listen()'ed socket; we
  425.        emulate that by closing it. */
  426.     close(fd);
  427.  
  428.     /* Cobble up the CIB structure for this connection.  The only thing
  429.        we don't yet have is the local port number. */
  430.     
  431.     if (getsockname(in_fd, (struct sockaddr *)&addr, &scratch) < 0) {
  432.       int the_err = errno;
  433.  
  434.       close(in_fd);
  435.       switch (the_err) {
  436.     case EBADF:
  437.       return E_BADHANDLE;
  438.     case EINVAL:
  439.     case EOPNOTSUPP:
  440.     default:
  441.       return -1000 - the_err;
  442.       }
  443.     }
  444.     if (!make_CIB(in_fd, P_TCP, addr.sin_port, port, hostaddr, 1)) {
  445.       close(in_fd);
  446.       return E_NOMEM;
  447.     }
  448.  
  449.     return in_fd;
  450.   }
  451. }
  452.  
  453. /* Incompatibility:  timeout is ignored */
  454. int16 do_TCP_close(int16 fd, int16 timeout)
  455. {
  456.   int ret;
  457.  
  458.   remove_CIB(fd);
  459.   ret = close(fd);
  460. #ifdef DEBUG
  461.   debug("sisi", "TCP_close(", fd, ") returns ", (ret < 0 ? E_BADCLOSE : 0));
  462. #endif
  463.   if (ret < 0)
  464.     return E_BADCLOSE;
  465.   else return 0;
  466. }
  467.  
  468. /* Incompatibility:  TCP_send() will probably be blocking; after all, I
  469.    can't return E_OBUFFULL in good faith if I don't honor obsize from
  470.    TCP_open(). */
  471. /* Incompatibility:  What is TCP_send() supposed to do if the non-blocking
  472.    TCP_open() hasn't finished?  The STiK specs don't give a clue; I'm
  473.    gonna just turn off O_NDELAY and wait for the connection to establish. */
  474. int16 do_TCP_send(int16 fd, char* buf, int16 buflen)
  475. {
  476.   int n, tot = 0;
  477.  
  478. #ifdef DEBUG
  479.   debug("sSs", "in TCP_send(\"", buflen, buf, "\")");
  480. #endif
  481.  
  482. #ifndef BLOCK_OPEN
  483.   if (!is_established(fd))
  484.     do_TCP_wait_state(fd, 0, 0);
  485. #endif
  486.  
  487.   for (;;) {
  488.     n = write(fd, buf + tot, buflen - tot);
  489.     if (n < 0) {
  490.       switch (errno) {
  491.     case EBADF:
  492.       return E_BADHANDLE;
  493.     case ENOSPC:
  494.       return E_NOMEM;
  495.     case ENXIO:
  496.       return E_LOSTCARRIER;
  497.     /* case EAGAIN: */
  498.     case ERANGE:
  499.       return E_OBUFFULL;
  500.     default:
  501.       return -1000 - errno;
  502.       }
  503.     } else {
  504.       tot += n;
  505.       if (tot >= buflen)
  506.     return E_NORMAL;
  507.     }
  508.   }
  509. }
  510.  
  511. /* Incompatibility:  Yeah, right, like I could reproduce the behavior of
  512.    this function...  Just select() on the socket; this works for waiting
  513.    for the non-blocking open to complete, which is probably the only
  514.    thing it gets used for. */
  515. int16 do_TCP_wait_state(int16 fd, int16 state, int16 timeout)
  516. {
  517.   auto fd_set read_set, write_set, except_set;
  518.   struct timeval T;
  519.   int n;
  520.  
  521. #ifdef DEBUG
  522.   debug("s", "in TCP_wait_state()");
  523. #endif
  524.  
  525. #ifndef BLOCK_OPEN
  526.   if (is_established(fd))
  527.     return E_NORMAL;
  528.  
  529.   n = fcntl(fd, F_GETFL);
  530.   fcntl(fd, F_SETFL, n & ~O_NDELAY);
  531.  
  532.   FD_ZERO(&read_set);
  533.   FD_SET(fd, &read_set);
  534.   FD_ZERO(&write_set);
  535.   FD_SET(fd, &write_set);
  536.   FD_ZERO(&except_set);
  537.   FD_SET(fd, &except_set);
  538.   T.tv_sec = timeout;
  539.   T.tv_usec = 0;
  540.  
  541.   n = select(fd + 1, &read_set, &write_set, &except_set, &T);
  542.   if (n == 0)
  543.     return E_USERTIMEOUT;
  544.   if (n > 0) {
  545.     set_establish(fd);
  546.     return E_NORMAL;
  547.   }
  548.   switch (errno) {
  549.     case EBADF:
  550.       return E_BADHANDLE;
  551.     case EINTR:
  552.     case EINVAL:
  553.     default:
  554.       return -1000 - errno;
  555.   }
  556. #else
  557.   return E_NORMAL;
  558. #endif /* BLOCK_OPEN */
  559. }
  560.  
  561. int16 do_UDP_open(uint32 hostaddr, int16 port)
  562. {
  563.   struct sockaddr_in addr;
  564.   int fd;
  565.   size_t scratch = sizeof(struct sockaddr_in);
  566.  
  567. #ifdef DEBUG
  568.   debug("s", "in UDP_open()");
  569. #endif
  570.   addr.sin_family = AF_INET;
  571.   addr.sin_addr.s_addr = hostaddr;
  572.   addr.sin_port = port;
  573.   memset(addr.sin_zero, 0, 8);
  574.  
  575.   fd = socket(AF_UNIX, SOCK_DGRAM, IPPROTO_UDP);
  576.   if (fd < 0) {
  577.     switch (errno) {
  578.       case EMFILE:
  579.     return E_NOCCB;
  580.       case ENOMEM:
  581.     return E_NOMEM;
  582.       case ENOENT:
  583.       case EAFNOSUPPORT:
  584.       case ESOCKTNOSUPPORT:
  585.       case EPROTONOSUPPORT:
  586.       case EPROTOTYPE:
  587.         return -1000 - errno;
  588.       default:
  589.     return E_CONNECTFAIL;
  590.     }
  591.   }
  592.  
  593.   if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
  594.     int the_err = errno;
  595.  
  596.     close(fd);
  597.     switch (the_err) {
  598.       case EBADF:
  599.       case EISCONN:
  600.     return E_BADHANDLE;
  601.       case EINVAL:
  602.     return E_LISTEN;
  603.       case ETIMEDOUT:
  604.     return E_CNTIMEOUT;
  605.       case ECONNREFUSED:
  606.     return E_REFUSE;
  607.       case EALREADY:
  608.       case EINPROGRESS:
  609.       case EINTR:
  610.     return fd;
  611.       case EAFNOSUPPORT:
  612.       case EDESTADDRREQ:
  613.       case EOPNOTSUPP:
  614.     return -1000 - the_err;
  615.       default:
  616.     return E_CONNECTFAIL;
  617.     }
  618.   }
  619.  
  620.   /* Cobble up the CIB structure for this connection.  The only thing
  621.      we don't yet have is the local port number. */
  622.   
  623.   if (getsockname(fd, (struct sockaddr *)&addr, &scratch) < 0) {
  624.     int the_err = errno;
  625.  
  626.     close(fd);
  627.     switch (the_err) {
  628.       case EBADF:
  629.     return E_BADHANDLE;
  630.       case EINVAL:
  631.       case EOPNOTSUPP:
  632.       default:
  633.     return -1000 - the_err;
  634.     }
  635.   }
  636.   if (!make_CIB(fd, P_UDP, addr.sin_port, port, hostaddr, 1)) {
  637.     close(fd);
  638.     return E_NOMEM;
  639.   }
  640.  
  641.   return fd;
  642. }
  643.  
  644. int16 do_UDP_close(int16 fd)
  645. {
  646.   int ret;
  647.  
  648. #ifdef DEBUG
  649.   debug("s", "in UDP_close()");
  650. #endif
  651.   remove_CIB(fd);
  652.   ret = close(fd);
  653.   if (ret < 0)
  654.     return E_BADCLOSE;
  655.   else return 0;
  656. }
  657.  
  658. int16 do_UDP_send(int16 fd, char* buf, int16 buflen)
  659. {
  660.   int n, tot = 0;
  661.  
  662. #ifdef DEBUG
  663.   debug("s", "in UDP_send()");
  664. #endif
  665.   n = write(fd, buf + tot, buflen - tot);
  666.   if (n < 0) {
  667.     switch (errno) {
  668.       case EBADF:
  669.     return E_BADHANDLE;
  670.       case ENOSPC:
  671.     return E_NOMEM;
  672.       case ENXIO:
  673.     return E_LOSTCARRIER;
  674.       case ERANGE:
  675.     return E_OBUFFULL;
  676.       default:
  677.     return -1000 - errno;
  678.     }
  679.   } else {
  680.     return E_NORMAL;
  681.   }
  682. }
  683.  
  684. /* This is just an estimate, but it should work. */
  685. int16 do_CNbyte_count(int16 fd)
  686. {
  687.   long l;
  688.  
  689.   if (fcntl(fd, FIONREAD, &l) < 0)
  690.     return -1000 - errno;
  691.   if (l == NO_LIMIT) {
  692. #ifndef BLOCK_OPEN
  693.     /* Tricky.  This could be either EOF or the connection not
  694.        established.  In the latter case, we have the "0 or E_NODATA?"
  695.        puzzler from below. */
  696.     if (!is_established(fd)) {
  697.       return 0;
  698.     }
  699. #endif
  700.     return E_EOF;
  701.   }
  702.   /* Now here's a puzzler.  If there's no data available should I return
  703.      0 or E_NODATA?  Dan Ackerman's mailer assumes the former, so that's
  704.      what I'll do. */
  705.   if (l == 0) {
  706.     /* Here's a sneaky trick:  If there's no data, surrender the rest of
  707.        our timeslice so that the STiK app doesn't eat all CPU time
  708.        spinning its wheels. */
  709.     Syield();
  710.     return 0;
  711.   }
  712. #ifdef DEBUG
  713.   debug("sdsl", "CNbyte_count(", fd, ") returns ", l);
  714. #endif
  715. #ifndef BLOCK_OPEN
  716.   /* I really don't like doing this here, since this function will
  717.      likely be called in a tight loop, but it has to be done, and this
  718.      is about the only place I can do it. */
  719.   set_establish(fd);
  720. #endif
  721.   return l;
  722. }
  723.  
  724. /* There should probably be a more efficient way of doing this than
  725.    calling read() */
  726. int16 do_CNget_char(int16 fd)
  727. {
  728.   char c;
  729.   int n;
  730.  
  731.   n = read(fd, &c, 1);
  732.   if (n > 0) {
  733. #ifndef BLOCK_OPEN
  734.     /* Again, I don't really like doing this here, but I don't think I
  735.        can avoid it. */
  736.     set_establish(fd);
  737. #endif
  738. #ifdef DEBUG
  739.     debug("sdscsxs", "CNget_char(", fd, ") returns '", c, "' (0x",
  740.       (unsigned)c, ")");
  741. #endif
  742.     return c;
  743.   }
  744.   if (n == 0) {
  745. #ifdef DEBUG
  746.     debug("sds", "CNget_char(", fd, ") returns EOF");
  747. #endif
  748.     return E_EOF;
  749.   }
  750. #ifdef DEBUG
  751.   debug("sdsd", "CNget_char(", fd, ") gets error code ", errno);
  752. #endif
  753.   switch (errno) {
  754.     case EWOULDBLOCK:
  755.       return E_NODATA;
  756.     case EBADF:
  757.       return E_BADHANDLE;
  758.     default:
  759.       return -1000 - errno;
  760.   }
  761. }
  762.  
  763. /* We fake this by reading whatever is there and building a a fake NDB
  764.    for it */
  765. NDB* do_CNget_NDB(int16 fd)
  766. {
  767.   int bufsize = do_CNbyte_count(fd);
  768.   char *buf;
  769.   NDB *ndb = 0;
  770.  
  771.   if (bufsize <= 0) {
  772.     return 0;
  773.   }
  774.   buf = do_KRmalloc(bufsize);
  775.   if (!buf) {
  776.     return 0;
  777.   }
  778.   ndb = (NDB *)do_KRmalloc(sizeof(NDB));
  779.   if (!ndb) {
  780.     do_KRfree(buf);
  781.     return 0;
  782.   }
  783.   bufsize = read(fd, buf, bufsize);
  784.   if (bufsize <= 0) {
  785.     do_KRfree(buf);
  786.     do_KRfree((char *)ndb);
  787.     return 0;
  788.   }
  789.   ndb->ptr = ndb->ndata = buf;
  790.   ndb->len = bufsize;
  791.   ndb->next = 0;
  792. #ifdef DEBUG
  793.   debug("sdsss", "CNget_NDB(", fd, ") returns |", ndb->ndata, "|");
  794. #endif
  795.   return ndb;
  796. }
  797.  
  798. /* Incompatibility:  CNget_block() is blocking, because there's no way
  799.    to say to MiNTnet, "If you can't fill the entire buffer in one try,
  800.    don't read anything" */
  801. int16 do_CNget_block(int16 fd, char* buf, int16 len)
  802. {
  803.   int n, tot = 0;
  804.  
  805. #ifndef BLOCK_OPEN
  806.   if (!is_established(fd))
  807.     do_TCP_wait_state(fd, 0, 0);
  808. #endif
  809.  
  810.   for (;;) {
  811.     n = read(fd, buf + tot, len - tot);
  812.     if (n > 0) {
  813.       tot += n;
  814.       if (tot >= len) {
  815. #ifdef DEBUG
  816.     debug("sisisss", "CNget_block(", fd, ", ", len, ") reads |", buf,
  817.           "|");
  818. #endif
  819.     return tot;
  820.       }
  821.     } else if (n == 0) {
  822.       /* Incompatibility:  If we read part of the buffer before getting
  823.      the EOF, there's no way to "unread" the read data.  I'm torn
  824.      between returning the number of bytes actually read and
  825.      trusting the caller to notice, or returning E_EOF and
  826.      discarding the partial buffer.  For now, I'll do the former. */
  827.       return tot;
  828.     } else {
  829.       switch (errno) {
  830.     case EWOULDBLOCK:
  831.       return E_NODATA;
  832.     case EBADF:
  833.       return E_BADHANDLE;
  834.     default:
  835.       return -1000 - errno;
  836.       }
  837.     }
  838.   }
  839. }
  840.  
  841. int16 do_resolve(char *hostname, char **realname, uint32 *addrs, int16 naddrs)
  842. {
  843.   register struct hostent *H = 0;
  844.   register char **raddr;
  845.   register int i;
  846.  
  847. #ifdef DEBUG
  848.   debug("ssspspsis", "in resolve(\"", hostname, "\", ", (void *)realname,
  849.              ", ", (void *)addrs, ", ", naddrs, ")");
  850. #endif
  851.   H = gethostbyname(hostname);
  852.   if (!H) {
  853. #ifdef DEBUG
  854.     debug("s", "gethostbyname() returns NULL");
  855. #endif
  856.     switch (h_errno) {
  857.       case HOST_NOT_FOUND:
  858.     return E_NOHOSTNAME;
  859.       case NO_DATA:
  860.     return E_DNSNOADDR;
  861.       case TRY_AGAIN:
  862.       case NO_RECOVERY:
  863.       default:
  864.     return E_CANTRESOLVE;
  865.     }
  866.   }
  867. #ifdef DEBUG
  868.   debug("sp", "  gethostbyname() returns ", (void *)H);
  869. #endif
  870.  
  871.   if (realname) {
  872. #ifdef DEBUG
  873.     debug("sss", "  copying name \"", H->h_name, "\"");
  874. #endif
  875.     *realname = do_KRmalloc(strlen(H->h_name) + 1);
  876.     strcpy(*realname, H->h_name);
  877.   }
  878.   /* BUG:  assumes addresses returned have type struct in_addr */
  879.   for (i = 0, raddr = H->h_addr_list; *raddr && i < naddrs; i++, raddr++) {
  880. #ifdef DEBUG
  881.     debug("sXsi",
  882.       "  copying address ", ((struct in_addr *)(*raddr))->s_addr,
  883.       " to array elmt ", i);
  884. #endif
  885.     addrs[i] = ((struct in_addr *)(*raddr))->s_addr;
  886.   }
  887.  
  888. #ifdef DEBUG
  889.   debug("si", "  returning ", i);
  890. #endif
  891.   return i;
  892. }
  893.  
  894. /* (possible) Incompatibility:  It is possible, at least in theory, for
  895.    find_CIB() to return NULL; the STiK specs seem to imply that this
  896.    cannot happen, so the receiving app probably doesn't check for it.
  897.    In practice, find_CIB() should not return NULL, except for file
  898.    descriptors that aren't sockets opened by GlueSTiK. */
  899. CIB* do_CNgetinfo(int16 fd)
  900. {
  901. #ifdef DEBUG
  902.   debug("s", "in do_CNgetinfo()");
  903. #endif
  904.   return find_CIB(fd);
  905. }
  906.